#!/bin/bash
########################################################################
####  Script Name: rbxi
####  Version: 2.7.3
####  Date: 2015-02-20
####  Copyright (C) Harald Hope 2006-2015
####
####  This program is free software; you can redistribute it and/or modify it under
####  the terms of the GNU General Public License as published by the Free Software
####  Foundation; either version 3 of the License, or (at your option) any later version.
####
####  This program is distributed in the hope that it will be useful, but WITHOUT
####  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
####  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
####
####  Get the full text of the GPL here: http://www.gnu.org/licenses/gpl.txt
####
####  This is an rdiff-backup/rsync script which helps automate the backup process
####  Requires companion excludes-....txt files to run, those must be in the rbxi-data
####  directory
####
####  rbxi.tar.bz2 package download URL: http://smxi.org/rb [contains all needed files]
####  Script Home page: http://techpatterns.com/forums/about831.html
########################################################################

########################################################################
####  CHANGES
####  2.7.3 2015-02-20 - updated date formats to: YYYY-MM-DD, fixed -J restart bug 
####    that made rbxi fail to return proper exit code on error after restart
####  2.7.2 4 September 2009 - last stable

########################################################################
####  VARIABLES
####  Make sure to change these to fit your installation
########################################################################

########################################################################
####  SCRIPT PATH VARIABLES
####--------------------------------------------------------------------

# Basic script layout markers
BA='=================================================================='
LI='------------------------------------------------------------------'

### if you do need to change one of these, make sure to change it in the
### user values file: rbxi-data/rbxi-values, not here, or you might lose
### your changes if you update this script.

### Script names/paths
# set this as absolute path for cron jobs if you need to, you'll have to
# update this manually every time you update the script:
LSOF='lsof'
LOGFILE_DIR='/var/log/'
SCRIPT_CONFIGS='/etc/rbxi.conf'
SCRIPT_NAME='rbxi'
SCRIPT_DATA='/rbxi-data/'
SCRIPT_README='readme-rbxi.htm'
SCRIPT_VALUES='rbxi-values'
# http://forums.macosxhints.com/archive/index.php/t-73839.html
# note, no other method works reliably to get the true script path, not dirname $0.
if type $LSOF &>/dev/null;then
	SCRIPT_PATH=$( dirname $( $LSOF -p $$ | grep 'REG' | grep -Eo "/.*$(basename $0)$" ) )
# checking if the dirname method works
elif [ -d "$( dirname $0 )$SCRIPT_DATA" ];then
	SCRIPT_PATH=$( dirname $0 )
fi

# in worst cases, you can manually set the script directory path here, uncomment and make the path
# explicit. Must not end with /, and must be the full path of the rbxi directory rbxi came with.
# you'll have to update this manually every time you update the script:
# example:  SCRIPT_PATH='/home/fred/scripts/rbxi'
# SCRIPT_PATH=''

SCRIPT_DATA_DIR="$SCRIPT_PATH$SCRIPT_DATA"
SCRIPT_VERSION_NUMBER=$( grep -im 1 'version:' $SCRIPT_PATH/$SCRIPT_NAME | awk '{print $3}' )
SCRIPT_DOWNLOAD='http://rbxi.googlecode.com/svn/trunk/'
SCRIPT_DOWNLOAD_BRANCH_1='http://rbxi.googlecode.com/svn/branches/one/'
SCRIPT_DOWNLOAD_BRANCH_2='http://rbxi.googlecode.com/svn/branches/two/'
SCRIPT_DOWNLOAD_DEV='http://smxi.org/tests/'

#### EXCLUDE LIST FILE NAMES
# NOTE: can be a blank file, but most be located in same directory as rbxi
# if you want them in a different directory, use absolute system paths.
EXCLUDE_ROOT='excludes-root.txt'
EXCLUDE_HOME='excludes-home.txt'
EXCLUDE_DATA_1='excludes-data-1.txt'
EXCLUDE_DATA_2='excludes-data-2.txt'
EXCLUDE_DATA_3='excludes-data-3.txt'
EXCLUDE_DATA_4='excludes-data-4.txt'
EXCLUDE_DATA_5='excludes-data-5.txt'
EXCLUDE_DATA_6='excludes-data-6.txt'
EXCLUDE_DATA_7='excludes-data-7.txt'
EXCLUDE_DATA_8='excludes-data-8.txt'
EXCLUDE_DATA_9='excludes-data-9.txt'
EXCLUDE_DATA_10='excludes-data-10.txt'
EXCLUDE_ROOT_RS='excludes-root-rsync.txt'
EXCLUDE_HOME_RS='excludes-home-rsync.txt'
EXCLUDE_DATA_1_RS='excludes-data-1-rsync.txt'
EXCLUDE_DATA_2_RS='excludes-data-2-rsync.txt'
EXCLUDE_DATA_3_RS='excludes-data-3-rsync.txt'
EXCLUDE_DATA_4_RS='excludes-data-4-rsync.txt'
EXCLUDE_DATA_5_RS='excludes-data-5-rsync.txt'
EXCLUDE_DATA_6_RS='excludes-data-6-rsync.txt'
EXCLUDE_DATA_7_RS='excludes-data-7-rsync.txt'
EXCLUDE_DATA_8_RS='excludes-data-8-rsync.txt'
EXCLUDE_DATA_9_RS='excludes-data-9-rsync.txt'
EXCLUDE_DATA_10_RS='excludes-data-10-rsync.txt'

########################################################################
####  USER SPECIFIC VARIABLES - REQUIRES rbxi-data/rbxi-values file
####--------------------------------------------------------------------

# initializing user defined functions/scripted actions/variables just to be safe, 
# must be prior to script rbxi-values sourcing
CONSOLE_BROWSER=''
EMAIL_START_ACTION=''
EMAIL_FINISH_ACTION=''
EMAIL_ERROR_ACTION=''
PRE_MOUNT_FUNCTION=''
POST_MOUNT_FUNCTION=''
POST_UMOUNT_FUNCTION=''

# variables that can be overridden in rbxi-values but which are commented out
LOGFILE_SIZE=100

## add in user variable values, sticky value file
# missing test will occur a bit later
if [ -f "$SCRIPT_DATA_DIR$SCRIPT_VALUES" ];then
	source $SCRIPT_DATA_DIR$SCRIPT_VALUES
fi

### See the file rbxi-data/rbxi-values for variable lists and how to
### set them. That file will be the actual data used.
### rbxi cannot run without the user data values file: rbxi-data/rbxi-values

########################################################################
####  STATIC VARIABLES, SHOULD NOT REQUIRE CHANGES
####--------------------------------------------------------------------

#### INITIALIZE VARIABLES TO BE SET ELSEWHERE
HOME_BACKUP=''
ROOT_BACKUP=''

# these are optional, only used if DATA_x_DIR is/are set
DATA_1_BACKUP=''
DATA_2_BACKUP=''
DATA_3_BACKUP=''
DATA_4_BACKUP=''
DATA_5_BACKUP=''
DATA_6_BACKUP=''
DATA_7_BACKUP=''
DATA_8_BACKUP=''
DATA_9_BACKUP=''
DATA_10_BACKUP=''

# backup command string holders
HOME_BU_COMMAND=''
ROOT_BU_COMMAND=''
DATA_1_BU_COMMAND=''
DATA_2_BU_COMMAND=''
DATA_3_BU_COMMAND=''
DATA_4_BU_COMMAND=''
DATA_5_BU_COMMAND=''
DATA_6_BU_COMMAND=''
DATA_7_BU_COMMAND=''
DATA_8_BU_COMMAND=''
DATA_9_BU_COMMAND=''
DATA_10_BU_COMMAND=''

# set initial value
ENDING_1='...'
ENDING_2='...'
# for timer function
START_TIME=$( date +%s )

# initialize internal booleans
B_CLONE_HOME='false'
B_CLONE_ROOT='false'
B_CLONE_DATA_1='false'
B_CLONE_DATA_2='false'
B_CLONE_DATA_3='false'
B_CLONE_DATA_4='false'
B_CLONE_DATA_5='false'
B_CLONE_DATA_6='false'
B_CLONE_DATA_7='false'
B_CLONE_DATA_8='false'
B_CLONE_DATA_9='false'
B_CLONE_DATA_10='false'
B_DELETE_STATUS='false'
B_DRY_RUN='false'
B_IS_CLONE='false'
# initialize globals to be set later
BACKUP_CLEAR=''
BACKUP_DURATION=''
# only for logging/history purposes
BACKUP_JOB_NAME=''
BACKUP_JOB_NU='none'
CLONE_SOURCE_DIR=''
DELETION_TEXT=''
# spinning wheel pid value
GET_PID=''
RSYNC_DELETE=''
SCRIPT_OPTIONS="$@"

###################################################################
#####  Functions
###################################################################

#### -------------------------------------------------------------------
#### Options/Parameters
#### -------------------------------------------------------------------

print_usage()
{
	if [ "$1" == 'err' ];then
		echo 'You entered an invalid option. Please use one of the following only:'
	fi
	echo '-A Add backup component. Overrides user set B_SKIP_DATA.. (d|h|hr|r|1-10)'
	echo '   d - add all DATA; h - add HOME; r - add ROOT; add DATA 1-10'
	echo '-b Automatic backup, non interactive.'
	echo '-B Change default backup directory (1-10).'
	echo '-c Automatic backup, clean older files, then runs non-interactive backup.'
	echo '-C (rsync only) Clone root/home. Skips all data backups. Moves files directly to mounted location'
	echo '   Sets the main mount subdirectory to '', then transfers files directly into that directory.'
	echo '   Takes parameters: (h|r|1-10). Clone root, home, or a data direcory.'
	echo '-d Automatic backup and delete, non interactive.'
	echo '-D Change default backup sub directory (1-10).'
	echo '-E Requires <1-10:1-10:1-10> for script start, finish, or error actions. Must be'
	echo '   one or more, but does not need to be all three. Actions are user created. See readme for how-to.'
	echo '-j Set script color scheme -j [0-5]: 0 - no colors; 1 - default, ok for dark/light or light/dark'
	echo '   2 - fancy dark on light; 3 - basic light on dark; 4 - fancy light on dark; 5 - smxi style'
	echo '-J Start preset backup job (1-10). Cannot be used with any other option.'
	echo '-l Use logging. Will override user rbxi-values setting.'
	echo "-L Create symbolic link in /usr/local/bin to $SCRIPT_NAME"
	echo '-m Skip the mounting option.'
	echo '-M use alternate mount/umount set (1-10)'
	echo '-o Override default backup application.'
	echo '-P Requires <1-10:1-10:1-10> for pre mount, post mount, or post umount extra functions. Must be'
	echo '   one or more, but does not need to be all three. Functions are user created. See readme for how-to.'
	echo '-r Trigger --dry-run for rsync. This simulates the backup, but does not actually run it.'
	echo '-R Show script readme file. Requires one of these console browsers (can also be set in rbxi-values):'
	echo '   links2 elinks w3m links lynx'
	echo '-s Show spinning wheel indicator.'
	echo '-S Skip backup component (d|h|hr|1-10)'
	echo '   d - skip all DATA; h - skip HOME; r - skip ROOT; skip DATA 1-10'
	echo '-U Update script manually from svn server.'
	echo '-v Show script version and last used information.'
	echo '-V Use alternate rbxi-values file. Syntax: rbxi-values-<whatever you want>'
	echo '   File must be located in rbxi-data, and must have the syntax of: rbxi-values-<something>'
	echo '-h This help menu'
	echo
	echo 'In general, avoid using A, D, M, S unless you are creating a backup job -J, or if you want'
	echo 'temporarily skip (-S) or add (-A) a specific directory.'
	echo
	echo '-S and -A can be used repeatedly, like so: -S 2 -S 5 -S 9'
	echo 'Remember, -A should only be used to override SKIP... that has been set in rbxi-values.'
	echo '-C overrides -A which overrides -S. -C will only clone the specific directory you set,'
	echo 'directly to the destination directory, and switches off all other backup directories.'
	echo '-C overrides -D, or default backup subdirectory, and sets it to null.'
	echo '-D overrides default main mount backup directory, and uses that for -M'
	exit 0
}

### this is not in a function because these variables need to be set on startup
# only use b or d, not both together. If you use both your old backups will be deleted.
# args: $1 - $@ - all args
# -A and -S can iterate repeatedly
get_options()
{
	local opt='' setDirectory='' setSubDir='' setMount='' setPrePost=''
	local setFullAdds='' setFullSkips='' setCloneData='' setEmailer=''

	while getopts :A:bB:cC:dD:E:hj:J:LlmM:o:P:rRsS:UvV:z:!: opt
	do
		case $opt in
			h)	print_usage
				;;
			A)	if [ -n "$( grep -E '^(d|h|r|rh|hr|[1-9]|10)$' <<< $OPTARG )" ];then
					setFullAdds="$setFullAdds $OPTARG"
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			b)	B_DO_BACKUP='true'
				;;
			B)	if [ -n "$( grep -E '^([1-9]|10)$' <<< $OPTARG )" ];then
					setDirectory="$OPTARG"
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			c)	B_CLEAN_OLDER='true'
				B_DO_BACKUP='true'
				;;
			C)	if [ -n "$( grep -E '^(r|h|[1-9]|10)$' <<< $OPTARG )" ];then
					setCloneData=$OPTARG
					B_IS_CLONE='true'
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			d)	B_DELETE_BACKUP='true'
				B_DO_BACKUP='true'
				;;
			D)	if [ -n "$( grep -E '^([1-9]|10)$' <<< $OPTARG )" ];then
					setSubDir="$OPTARG"
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			E)	if [ -n "$( grep -E '^([1-9]|10)?:([1-9]|10)?:([1-9]|10)?$' <<< $OPTARG )" ];then
					setEmailer="$OPTARG"
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			j)	if [ -n "$( grep -E '^([0-5])$' <<< $OPTARG )" ];then
					COLOR_SCHEME=$OPTARG
					set_script_colors
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			J)	if [ -n "$( grep -E '^([1-9]|10)$' <<< $OPTARG )" ];then
					set_or_print_backup_job "$OPTARG" 'set'
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			l)	B_LOGGING='true'
				;;
			L) create_symbolic_link
				exit 0
				;;
			m)	B_SKIP_MOUNT='true'
				;;
			M)	if [ -n "$( grep -E '^([1-9]|10)$' <<< $OPTARG )" ];then
					setMount="$OPTARG"
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			o)	if [ -n "$( grep -E '^(rd|rs)$' <<< $OPTARG )" ];then
					case $OPTARG in
						rd)
							BACKUP_APP='rdiff-backup'
							;;
						rs)
							BACKUP_APP='rsync'
							;;
					esac
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			P)	if [ -n "$( grep -E '^([1-9]|10)?:([1-9]|10)?:([1-9]|10)?$' <<< $OPTARG )" ];then
					setPrePost="$OPTARG"
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			r)	B_DRY_RUN='true'
				;;
			R)	show_script_readme
				exit
				;;
			s)	B_SPINNING_WHEEL='true'
				ENDING_1=': '
				ENDING_2=', watch the spinning wheel: '
				;;
			S)	if [ -n "$( grep -E '^(d|h|r|rh|hr|[1-9]|10)$' <<< $OPTARG )" ];then
					setFullSkips="$setFullSkips $OPTARG"
				else
					error_handler 13 "-$opt $OPTARG"
				fi
				;;
			U)	script_self_updater "$SCRIPT_DOWNLOAD" 'svn server'
				;;
			v)	print_version_info 'opt'
				exit 0
				;;
			V)	# construct new user values file name, then test it, load it
				SCRIPT_VALUES="$SCRIPT_VALUES-$OPTARG"
				if [ -f "$SCRIPT_DATA_DIR$SCRIPT_VALUES" ];then
					source $SCRIPT_DATA_DIR$SCRIPT_VALUES
					set_script_colors
					check_script_requires
				else
					error_handler 22
				fi
				;;
			# set_or_print_backup_job will relaunch with job options and -z has the bu job nu for output
			z)	if [ -n "$( grep -E '^([1-9]|10)$' <<< $OPTARG )" ];then
					BACKUP_JOB_NU=$OPTARG
				fi
				;;
			!)	# test for various supported methods
				case $OPTARG in
					1)	B_TESTING_1='true'
						;;
					2)	B_TESTING_2='true'
						;;
					3)	B_TESTING_1='true'
						B_TESTING_2='true'
						;;
					10) script_self_updater "$SCRIPT_DOWNLOAD_DEV" 'dev server'
						;;
					11)	script_self_updater "$SCRIPT_DOWNLOAD_BRANCH_1" 'svn: branch one server'
						;;
					12)	script_self_updater "$SCRIPT_DOWNLOAD_BRANCH_2" 'svn: branch two server'
						;;
					http*)
						script_self_updater "$OPTARG" 'alt server'
						;;
					*)	error_handler 11 "-$opt $OPTARG"
						;;
				esac
				;;
			*)	error_handler 7 "-$OPTARG"
				;;
		esac
	done
	# note, because mount will use the first value, I have to set this here, to
	# ensure the proper order. Or you can just set the stuff manually in your rbxi-values file
	# Clone -C overrides Adds -A override skips -S. -A and -S can handle multiple iterations.
	# -C overrides -D, backup subdirectory, and sets it to null
	# -D overrides default main backup directory for -M
	if [ -n "$setDirectory" ];then
		set_backup_mount_point "$setDirectory"
	fi
	if [ -n "$setSubDir" ];then
		set_backup_mount_point_directory "$setSubDir"
	fi
	if [ -n "$setFullSkips" ];then
		set_skip_data "$setFullSkips"
	fi
	if [ -n "$setFullAdds" ];then
		set_add_data "$setFullAdds"
	fi
	if [ -n "$setCloneData" ];then
		set_clone_data "$setCloneData"
	fi
	if [ -n "$setMount" ];then
		set_mount_data "$setMount"
	fi
	if [ -n "$setEmailer" ];then
		set_emailer_data "$setEmailer"
	fi
	if [ -n "$setPrePost" ];then
		set_pre_post_data "$setPrePost"
	fi
}

#### -------------------------------------------------------------------
#### Error Handling
#### -------------------------------------------------------------------


# Error handling
# args: $1 - error number; $2 - optional, extra information
error_handler()
{
	local error_message='' errorType='' extra2='' extra3='' cleanedMessage=''

	case $1 in
		50)
			errorType="Event"
			W=${M}
			;;
		*)
			errorType="Error"
			;;
	esac

	# assemble the error message
	case $1 in
		2)	error_message="The component: ${C}MOUNT_BU_DISK${W} failed to successfully complete its task. Error code was: ${C}$2"
			;;
		3)	error_message="The component: ${C}UNMOUNT_BU_DISK${W} failed to successfully complete its task. Error code was: ${C}$2"
			;;
		4)	error_message="You must be logged in as ${C}root${W} to run this script."
			;;
		5)	error_message="dependency not met: ${C}$2${W} not found in path"
			;;
		6)	error_message="Your backup partition/directory ${C}$BACKUP_MOUNT_POINT${W} is not present.\nPlease make sure to create it or mount it up before you proceed."
			;;
		7)	error_message="One of the options you entered in your script parameters: ${C}$2${W}\nIs not supported, or requires a further argument.\nFor a list of supported options, check the help menu: ${C}$SCRIPT_NAME -h"
			;;
		8)	error_message="the self-updater failed, wget exited with error: ${C}$2${W}.\nYou probably need to be root.\nHint, to make for easy updates without being root, do: chown <user name> ${C}$SCRIPT_PATH/$SCRIPT_NAME"
			;;
		9)	error_message="unset"
			;;
		10)
			error_message="the alt download url you provided: ${C}$2${W}\nappears to be wrong, download aborted. Please note, the url\nneeds to end in ${C}/${W}, without ${C}$SCRIPT_NAME${W}, like: ${C}http://yoursite.com/downloads/"
			;;
		11)
			error_message="unsupported testing option argument: ${C}-! $2"
			;;
		12)
			error_message="the svn branch download url: ${C}$2${W}\nappears to be empty currently. Make sure there is an actual svn branch version\nactive before you try this again. Check http://code.google.com/p/inxi\nto verify the branch status."
			;;
		13)
			error_message="The option argument you gave is not supported: ${C}$2"
			;;
		14)
			error_message="You do not have the required backup application installed. Missing: ${C}$2"
			;;
		15)
			error_message="You cannot use both ${C}-c${W} and ${C}-d${W}, only one or the other. Either you are clearing, or deleting."
			;;
		16)
			error_message="${C}B_VARIABLES_SET='false'${W} in the file ${C}rbxi-data/$SCRIPT_VALUES${W} must be set to ${C}'true' before you can run $SCRIPT_NAME\nYou must configure that file first, then when you're done, you can the script."
			;;
		17)
			error_message="The backup job you selected (${C}$2${W}) is empty. Please make sure you entered the right number."
			;;
		18)
			error_message="The backup directory you selected (${C}$2${W}) is empty.\nYou cannot backup to, or mount, a blank directory."
			;;
		19)
			error_message="Your backup program ${C}$BACKUP_APP${W} does not support the -C clone option."
			;;
		20)
			error_message="The backup source directory: ${C}$2${W} does not exist. Unable to continue."
			;;
		21)
			error_message="You are using an unsupported color scheme: ${C}$2"
			;;
		22)
			error_message="Could not load user values file: ${C}$SCRIPT_DATA_DIR$SCRIPT_VALUES${W}\nPlease double check that the file exists and is in: ${C}$SCRIPT_DATA_DIR${W}\nExiting now."
			;;
		23)
			error_message="Unable to locate the script data directory: ${C}$SCRIPT_PATH$SCRIPT_DATA\n${C}rbxi${W} requires the program ${C}$2${W} to create its paths if you start using a symbolic link.\nYou must install this application before you can run ${C}$SCRIPT_NAME${W} with a sybolic link.\nUnable to continue."
			;;
		24)
			error_message="Your backup destination directory: ${C}$2${W}\ndoes not seem to exist. Please check your settings and make sure the directory\nyou are using actually exists."
			;;
		25)
			error_message="Your backup application ${C}$BACKUP_APP${W} exited with error: ${C}$2${W}\nPlease check the source of the error and try again. Exiting $SCRIPT_NAME now."
			;;
		26)
			error_message="The variable ${C}BACKUP_MOUNT_POINT${W} is empty. Backup directory mount cannnot continue."
			;;
		27)
			error_message="The function: ${C}pre_mount_tasks${W} exited with error code: (${C}$2${W})"
			;;
		28)
			error_message="The function: ${C}post_mount_tasks${W} exited with error code: (${C}$2${W})"
			;;
		29)
			error_message="The function: ${C}post_umount_tasks${W} exited with error code: (${C}$2${W})"
			;;
		30)
			error_message="The rbxi log directory ${C}$2${W} does not exist.\nPlease correct the path in rbxi-values LOGFILE_DIR='' before continuing."
			;;
		31)
			error_message="User set Action returned error: $2"
			;;
		32)
			error_message="No console browser detected in your system. Requires one of these: links2 elinks w3m links lynx"
			;;
		50)
			error_message="User initiated script termination. Exiting $SCRIPT_NAME now."
			;;
		100)
			error_message="$SCRIPT_NAME does not yet support the backup app you requested: ${C}$2${W}\nThis support should be coming sometime soon.\nCurrently supported backup applications are: rdiff-backup."
			umount_backup_disk
			;;
		*)	error_message="Unknown error number: ${C}$1"
			;;
	esac
	log_function_data 'error' "$errorType ($1)\n$error_message"
	run_emailer_tasks 'error' "$errorType ($1)\n$error_message"
	# then print it and exit
	echo -e "${W}$errorType ${C}$1${W}: $error_message${N}"
	exit $1
}

# args: $1 type: start/error/data; $2 - data to be logged
log_function_data()
{
	if [ "$B_LOGGING" == 'true' ];then
		local data=$( echo -e "$2" | sed 's/\x1b\[[0-9]\{1,2\}\(;[0-9]\{1,2\}\)\{0,2\}m//g' )
		local actionTime=$( date +"%R:%S" )
		local logFile=${LOGFILE_DIR}${SCRIPT_NAME}.log

		# check user error first
		if [ ! -d $LOGFILE_DIR ];then
			error_handler 30 "$LOGFILE_DIR"
		fi
		# I don't to try to handle various distro logrotate tools, so I'm making my own here
		# going to rotate it at 100kB
		if [ -f $logFile ];then
			# this shouldn't have been necessary, but if on same line as -f test, gives error
			# if no file exists.
			if [ "$( du -s $logFile | awk '{print $1}' )" -gt $LOGFILE_SIZE ];then
				mv -f $logFile ${LOGFILE_DIR}${SCRIPT_NAME}.1.log
			fi
		fi
		# then make sure the file is ready to go
		if [ ! -f $logFile ];then
			touch $logFile
		fi
		case $1 in
			start)
				echo $BA >> $logFile
				echo "Starting $SCRIPT_NAME at: $( date +"%Y %B %e - %R:%S" )" >> $logFile
				echo "Script start options: $2" >> $logFile
				echo $LI >> $logFile
				if [ -f $SCRIPT_CONFIGS -a -n "$( cat $SCRIPT_CONFIGS )" ];then
					echo "Previous Script Config Data:" >> $logFile
					echo "$( cat $SCRIPT_CONFIGS )" >> $logFile
				else
					echo "Previous Script Config Data File Is Null." >> $logFile
				fi
				echo $LI >> $logFile
				echo "Starting backup job." >> $logFile
				;;
			error|data)
				echo -e "$actionTime: $data" >> $logFile
				;;
		esac
	fi
}

#### -------------------------------------------------------------------
#### Utilities
#### -------------------------------------------------------------------

# set global color variables
# options: 0 - no colors; 1 - defaults; 2 light bkgd, fancy; dark background, simple
# 4 dark background, fancy; 4 smxi
set_script_colors()
{
	# set colors # ="[40m" # black background
	case "$COLOR_SCHEME" in
		# colors off
		0)
			W='' # Warning message
			E='' # script Error
			S='' # Standard message
			Q='' # Questions
			M='' # Message
			C='' # Command or Path
			N='' # default system console color: Normal :: make last in colors
			;;
		# default, either dark or light background
		''|1)
			W="[0;31m" # Warning message
			E="[1;31m" # script Error
			S="[0;39m" # Standard message
			Q="[1;39m" # Questions
			M="[1;39m" # Message
			C="[0;35m" # Command or Path
			B="[0;39m" # black background
			N="[0;39m" # default system console color: Normal
			;;
		# light background, fancy
		2)
			W="[0;31m" # Warning message
			E="[1;31m" # script Error
			S="[0;39m" # Standard message
			Q="[1;34m" # Questions
			M="[1;34m" # Message
			C="[0;35m" # Command or Path
			B="[0;34m" # black background
			N="[0;39m" # default system console color: Normal :: make last in colors
			;;
		# dark background, simple
		3)
			W="[1;31m" # Warning message
			E="[1;33m" # script Error
			S="[0;39m" # Standard message
			Q="[1;39m" # Questions
			M="[1;39m" # Message
			C="[1;35m" # Command or Path
			B="[0;39m" # black background
			N="[0;39m" # default system console color: Normal
			;;
		# dark background, fancy
		4)
			W="[1;31m" # Warning message
			E="[1;33m" # script Error
			S="[0;39m" # Standard message
			Q="[1;36m" # Questions
			M="[1;36m" # Message
			C="[1;35m" # Command or Path
			B="[0;34m" # black background
			N="[0;39m" # default system console color: Normal :: make last in colors
			;;
		# dark background, smxi style
		5)
			W="[0;31m" # red: Warning message
			E="[0;33m" # yellow: script Error
			S="[1;32m" # green: Standard message
			Q="[1;36m" # CYAN: Questions
			M="[1;36m" # CYAN: Message
			C="[1;35m" # MAGENTA: Command or Path
			B="[1;34m" # BLUE: Message
			N="[0;39m" # default system console color: Normal :: make last in colors
			;;
		*)
			error_handler 21 "$COLOR_SCHEME"
			;;
	esac

	# script layout stuff
	BAR=${S}$BA${N}
	EBAR=${E}$BA${N}
	WBAR=${W}$BA${N}
	MBAR=${M}$BA${N}
	LINE=${S}$LI${N}
	ELINE=${E}$LI${N}
	MLINE=${M}$LI${N}
	WLINE=${W}$LI${N}
	SPACER='  '
}

create_symbolic_link()
{
	local ulbLink="/usr/local/bin/$SCRIPT_NAME"
	local scriptInPath=$( which $SCRIPT_NAME | grep -v "./$SCRIPT_NAME" )

	if [ ! -L $ulbLink -a ! -f $ulbLink -a -z "$scriptInPath" ];then
		check_is_root
		# only do the linking if the path is real
		if type $LSOF &>/dev/null;then
			echo "${S}Creating link now...${N}"
			ln -s $SCRIPT_PATH/$SCRIPT_NAME $ulbLink
		else
			echo "${C}$SCRIPT_PATH ${W}is not properly set, cannot automatically create symbolic link.${N}"
		fi
	else
		echo "${M}$SCRIPT_NAME is already in your system path, or a link to it already exists.${N}"
	fi
}

# args: $1 - main/v
print_history_data()
{
	local lastBackupDirectory='Unset'
	local lastBackupDate='Unset'
	local lastBackupDuration='Unset'
	local lastBackupApp='Unset'
	local lastBackupJobNu='Unset'
	local rdbuHistoryHolder=''
	local rsyncHistoryHolder=''
	local rdbuHistory='Unset'
	local rsyncHistory='Unset'
	local rdbuHistory2=''
	local rsyncHistory2=''

	if [ "$1" != 'main' ];then
		M=''
		C=''
		N=''
		S=''
	fi

	if [ -f $SCRIPT_CONFIGS ];then
		lastBackupDirectory=$( grep 'last-backup-directory=' $SCRIPT_CONFIGS | cut -d '=' -f 2 )
		lastBackupDate=$( grep 'last-backup-date=' $SCRIPT_CONFIGS | cut -d '=' -f 2 )
		lastBackupDuration=$( grep 'last-backup-duration=' $SCRIPT_CONFIGS | cut -d '=' -f 2 )
		lastBackupApp=$( grep 'last-backup-app=' $SCRIPT_CONFIGS | cut -d '=' -f 2 )
		lastBackupJobNu=$( grep 'last-backup-job=' $SCRIPT_CONFIGS | cut -d '=' -f 2 )
		# add line breaks because output is too long for single line
		rdbuHistoryHolder="$( grep 'rdbu-backup-history=' $SCRIPT_CONFIGS | cut -d '=' -f 2 )"
		rsyncHistoryHolder="$( grep 'rsync-backup-history=' $SCRIPT_CONFIGS | cut -d '=' -f 2 )"
		rdbuHistory="$( cut -d '~' -f 1 <<< $rdbuHistoryHolder )"
		rsyncHistory="$( cut -d '~' -f 1 <<< $rsyncHistoryHolder )"

		if [ -n "$( grep '~' <<< $rdbuHistoryHolder )" ];then
			rdbuHistory2="$( cut -d '~' -f 2 <<< $rdbuHistoryHolder )"
			rdbuHistory2='echo "                      ${C}'$rdbuHistory2'${N}"'
		fi
		if [ -n "$( grep '~' <<< $rsyncHistoryHolder )" ];then
			rsyncHistory2="$( cut -d '~' -f 2 <<< $rsyncHistoryHolder )"
			rsyncHistory2='echo "                      ${C}'$rsyncHistory2'${N}"'
		fi
	fi
	echo "${M}Last Backup Date: ${C}$lastBackupDate${N}"
	echo "${M}Last Backup Directory: ${C}$lastBackupDirectory${N}"
	echo "${M}Last Backup Program: ${C}$lastBackupApp${N}"
	if [ "$lastBackupJobNu" == 'none' ];then
		echo "${M}Your last backup did not use the ${C}Job${M} feature.${N}"
	else
		echo "${M}Last Backup Job Number: ${C}$lastBackupJobNu${N}"
	fi
	if [ "$1" == 'main' ];then
		case "$BACKUP_APP" in
			rdiff-backup)
				echo "${M}Rdiff-backup history: ${C}$rdbuHistory${N}"
				eval "$rdbuHistory2"
				;;
			rsync)
				echo "${M}Rsync backup history: ${C}$rsyncHistory${N}"
				eval "$rsyncHistory2"
				;;
		esac
	else
		echo "${M}Rdiff-backup history: ${C}$rdbuHistory${N}"
		eval "$rdbuHistory2"
		echo "${M}Rsync backup history: ${C}$rsyncHistory${N}"
		eval "$rsyncHistory2"
	fi
}

## print out version information for -v
print_version_info()
{
	local last_modified=$( grep -im 1 'date:' $SCRIPT_PATH/$SCRIPT_NAME | awk '{print $3,$4,$5}' )
	local versionRemote='' versionRemoteDate='' versionRemoteNumber='' remoteNotify=''

	if [ "$B_UPDATE_NOTIFIER" == 'true' ];then
		versionRemote=$( check_remote_version )
		versionRemoteDate=$( cut -d ':' -f 2 <<< $versionRemote )
		versionRemoteNumber=$( cut -d ':' -f 1 <<< $versionRemote )
		if [ "$versionRemoteNumber" != "$SCRIPT_VERSION_NUMBER" ];then
			remoteNotify='echo " ${M}(Newer version available: ${C}$versionRemoteNumber${M} Release Date: ${C}$versionRemoteDate${M})${N}"'
		fi
	fi

	if [ "$1" == 'opt' ];then
		echo $LINE
		echo "$SCRIPT_NAME - the universal, portable, system backup script."
		echo "Version: $SCRIPT_VERSION_NUMBER"
		echo "Script Last Modified: $last_modified"
		echo "Script Location: $SCRIPT_PATH${N}"
		print_history_data
	elif [ "$1" == 'main' ];then
		echo " ${C}$SCRIPT_NAME${S} ${M}:: Version: ${C}$SCRIPT_VERSION_NUMBER${S} ${M}:: Released: ${C}$last_modified${N}"
		eval "$remoteNotify"
	fi
}

# args: $1 - download url, not including file name; $2 - string to print out
# note that $1 must end in / to properly construct the url path
script_self_updater()
{
	local wget_error=0
	local ua='-U s-tools/rbxi.updater'

	echo "Starting $SCRIPT_NAME self updater."
	echo "Currently running $SCRIPT_NAME version number: $SCRIPT_VERSION_NUMBER"
	echo "Updating $SCRIPT_NAME in $SCRIPT_PATH using $2 as download source..."
	# first test if path is good, need to make sure it's good because we're -O overwriting file
	wget -q --spider $1$SCRIPT_NAME || wget_error=$?
	# then do the actual download
	if [[ $wget_error -eq 0 ]];then
		wget $ua -q -O $SCRIPT_PATH/$SCRIPT_NAME $1$SCRIPT_NAME || wget_error=$?
		if [[ $wget_error -eq 0 ]];then
			SCRIPT_VERSION_NUMBER=$( grep -im 1 'version:' $SCRIPT_PATH/$SCRIPT_NAME | awk '{print $3}' )
			echo "Successfully updated to $2 version: $SCRIPT_VERSION_NUMBER"
			echo "To run the new version, just start $SCRIPT_NAME again."
			exit 0
		fi
	fi
	# now run the error handlers on any wget failure
	if [[ $wget_error -gt 0 ]];then
		if [[ $2 == 'svn server' ]];then
			error_handler 8 "$wget_error"
		elif [[ $2 == 'alt server' ]];then
			error_handler 10 "$1"
		else
			error_handler 12 "$1"
		fi
	fi
}

show_script_readme()
{
	local browser='' browser_path=''
	
	for browser in $CONSOLE_BROWSER links2 elinks w3m links lynx
	do
		if [ -n "$( which $browser )" ];then
			browser_path=$( which $browser )
			break
		fi
	done
	if [ -n "$browser_path" ];then
		$browser_path $SCRIPT_PATH$SCRIPT_DATA$SCRIPT_README
	else
		error_handler 32
	fi
}

# creates the spinning wheel if script starts with -s option, and shows completion
spinning_wheel_activity_indicator()
{
	local completionText=''

	if [ "$1" == 'delete' ];then
		completionText='backup directories removed'
	fi
	if [ "$1" == 'backup' ];then
		completionText="$2 backed up"
	fi

	echo -n ${S}
	# while kill -0 $GET_PID
	while [ -e /proc/$GET_PID ]
	do
		sleep $SLEEP_TIME_SPINNER
		echo -n '|'
		echo -ne "\b"
		sleep $SLEEP_TIME_SPINNER
		echo -n '/'
		echo -ne "\b"
		sleep $SLEEP_TIME_SPINNER
		echo -n '-'
		echo -ne "\b"
		sleep $SLEEP_TIME_SPINNER
		echo -n "\\"
		echo -ne "\b"
	done
	echo -ne "\b $completionText"
	echo ${N}
}

# args: $1 umount/
trap_handler()
{
	local i=''

 	case "$1" in
 		umount)
 			echo
 			echo "${S}You are leaving $SCRIPT_NAME with the backup partition still mounted!"
 			echo "Waiting a few seconds to let disk writes sync before exiting...${N}"
 			# give the disk time sync its writes before umount...
 			# set in rbxi-values if you need to increase or decrease the time for premature
 			# or forced script exit for umount operation to work successfully.
 			for (( i=0; i < $SLEEP_TIME_UMOUNT; i++ ))
 			do
 				echo -n "${M}...tick${N}"
 				sleep $i
 			done
 			echo "${M}...done!${N}"
 			umount_backup_disk
 			run_pre_post_tasks 'post-umount'
 			# set trap to null to avoid loops for final exits
			trap - INT TERM EXIT
 			error_handler 50
 			;;
 	esac
}

#### -------------------------------------------------------------------
#### basic tests
#### -------------------------------------------------------------------

# this will load/test anything that is required
check_script_requires()
{
	# this test handles three cases:
	# 1: constructing a path with possibly user hard-coded value for SCRIPT_PATH fails
	# 2: constructing the path with dirname and rbxi-data fails to detect a directory
	# 3: lsof does not exit in system
	if [ ! -d "$SCRIPT_PATH$SCRIPT_DATA" ] && [ ! -d "$( dirname $0 )$SCRIPT_DATA" ] && ! type $LSOF &>/dev/null;then
		error_handler 23 'lsof'
	fi
	## add in user variable values, sticky value file
	if [ ! -f "$SCRIPT_DATA_DIR$SCRIPT_VALUES" ];then
		error_handler 22
	fi
}

check_is_root()
{
	if [ "$( whoami )" != "root" ];then
		error_handler 4
	fi
}

check_startup_stuff()
{
	check_is_root
	create_etc_configs
	check_bu_app_installed
	if [ "$B_CLEAN_OLDER" == 'true' -a "$B_DELETE_BACKUP" == 'true' ];then
		error_handler 15
	fi
	if [ "$B_VARIABLES_SET" != 'true' ];then
		error_handler 16
	fi
	if [ "$B_IS_CLONE" == 'true' -a "$BACKUP_APP" != 'rsync' ];then
		error_handler 19
	fi
}

check_script_path()
{
	local ExDir=$( dirname $0 )

	if [ "$( pwd )" != "$ExDir" -a "$ExDir" != '.' ];then
		cd $ExDir
	fi
}

check_script_changes()
{
	local oldBuMount='BACKUP_DIRECTORY'
	local oldBuMountSub='BACKUP_SUB_DIR'
	local updateBuMount=$( egrep "($oldBuMount|$oldBuMountSub)" $SCRIPT_DATA_DIR$SCRIPT_VALUES $SCRIPT_DATA_DIR$SCRIPT_README )

	if [ -n "$updateBuMount" ];then
		echo "${S}Updating your $SCRIPT_VALUES $SCRIPT_README files to use new variable names:"
		echo "BACKUP_MOUNT_POINT replaces BACKUP_DIRECTORY"
		echo "BACKUP_MOUNT_POINT_DIRECTORY replaces BACKUP_SUB_DIR"
		echo "Please restart $SCRIPT_NAME after this is completed.${N}"
		sed -i 's/BACKUP_DIRECTORY/BACKUP_MOUNT_POINT/g' $SCRIPT_DATA_DIR$SCRIPT_VALUES $SCRIPT_DATA_DIR$SCRIPT_README
		sed -i 's/BACKUP_SUB_DIR/BACKUP_MOUNT_POINT_DIRECTORY/g' $SCRIPT_DATA_DIR$SCRIPT_VALUES $SCRIPT_DATA_DIR$SCRIPT_README
		sed -i 's/2\.5\.[0-1]/2.5.2/g' $SCRIPT_DATA_DIR$SCRIPT_VALUES $SCRIPT_DATA_DIR$SCRIPT_README
		echo "${S}Updated and exiting. Please restart $SCRIPT_NAME, sorry for the inconvenience.${N}"
		exit 0
	fi
}

check_bu_app_installed()
{
	local pathExists='' appToCheck=''
	# this must set error to /dev/null to avoid false positive in some cases
	local appWhich="$( which $BACKUP_APP )"

	# more handling is required for cron jobs, which might not show which output
	case $BACKUP_APP in
		rdiff-backup)
			appToCheck=$RDIFF_PATH
			;;
		rsync)
			appToCheck=$RSYNC_PATH
			;;
	esac
	# checking the actual paths here, not relying on unreliable which output
	if [ ! -x "$appWhich" -a ! -x $appToCheck ];then
		error_handler 14 $BACKUP_APP
	fi
}

# check to see if its' a local or remote directory
# args: $1 - directory path, check for :/ or @
check_directory_remote()
{
	local isRemote=$( grep -E '(:/)' <<< "$1" )

	if [ -d "$1" -o -n "$isRemote" ];then
		return 0
	else
		return 1
	fi
}

# args: $1 - directory full path to check
check_backup_source_directory()
{
	check_directory_remote "$1"
	local returnIs="$?"

	echo -n "${S}Checking backup source ${C}$1${S}....${N}"
	if [ "$returnIs" -eq 0 ];then
		echo "${S}....${M}valid${N}"
	else
		echo "${S}....${W}INVALID${N}"
		error_handler 20 "$1"
	fi
}

# args: $1 - backup destination local directory
check_backup_destination_directory()
{
	check_directory_remote "$1"
	local returnIs="$?"

	echo -n "${S}Checking backup destination ${C}$1${S}....${N}"
	if [ "$returnIs" -eq 0 ];then
		echo "${S}....${M}valid${N}"
	else
		echo "${S}....${W}INVALID${N}"
		error_handler 24 "$1"
	fi
}

check_remote_version()
{
	local versionRemote=''
	local ua='-U s-tools/rbxi.rb-version'

	# get ip using wget redirect to stdout. This is a clean, text only IP output url.
	versionRemote=$( wget $ua -q -O - http://smxi.org/rb/rb-version | grep 'rbxi=' | cut -d '=' -f 2 )
	echo "$versionRemote"
}

create_etc_configs()
{
	if [ ! -f $SCRIPT_CONFIGS ];then
		touch $SCRIPT_CONFIGS
		echo 'last-backup-directory=Unset' >> $SCRIPT_CONFIGS
		echo 'last-backup-date=Unset' >> $SCRIPT_CONFIGS
		echo 'last-backup-duration=Unset' >> $SCRIPT_CONFIGS
	fi
	if [ -z "$( grep 'rdbu-backup-history=' $SCRIPT_CONFIGS )" ];then
		echo 'rdbu-backup-history=Unset' >> $SCRIPT_CONFIGS
	fi
	if [ -z "$( grep 'rsync-backup-history=' $SCRIPT_CONFIGS )" ];then
		echo 'rsync-backup-history=Unset' >> $SCRIPT_CONFIGS
	fi
	if [ -z "$( grep 'last-backup-app=' $SCRIPT_CONFIGS )" ];then
		echo 'last-backup-app=Unset' >> $SCRIPT_CONFIGS
	fi
	if [ -z "$( grep 'last-backup-job=' $SCRIPT_CONFIGS )" ];then
		echo 'last-backup-job=Unset' >> $SCRIPT_CONFIGS
	fi
}

#### -------------------------------------------------------------------
#### set data functions - primary, directory, backup commands, mount
#### -------------------------------------------------------------------

# load proper values for locations and command strings
set_primary_backup_data()
{
	case "$BACKUP_APP" in
		rsync)
			# update global file names.
			# First make sure no user error with the directory name occured with options
			if [ -z "$BACKUP_MOUNT_POINT_RS" ];then
				error_handler 18 'BACKUP_MOUNT_POINT_RS'
			fi
			# then remove this data, since we only use the primary directories
			if [ "$B_IS_CLONE" == 'true' ];then
				BACKUP_MOUNT_POINT_DIRECTORY_RS=''
			fi

			# note: these values were set in set_backup_mount_point
			# and set_backup_mount_point_directory if -B or -D were used
			# note: this is required for mounts
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_RS
			BACKUP_LOCATION=$BACKUP_MOUNT_POINT_RS$BACKUP_MOUNT_POINT_DIRECTORY_RS
			EXCLUDE_ROOT=$EXCLUDE_ROOT_RS
			EXCLUDE_HOME=$EXCLUDE_HOME_RS
			EXCLUDE_DATA_1=$EXCLUDE_DATA_1_RS
			EXCLUDE_DATA_2=$EXCLUDE_DATA_2_RS
			EXCLUDE_DATA_3=$EXCLUDE_DATA_3_RS
			EXCLUDE_DATA_4=$EXCLUDE_DATA_4_RS
			EXCLUDE_DATA_5=$EXCLUDE_DATA_5_RS
			EXCLUDE_DATA_6=$EXCLUDE_DATA_6_RS
			EXCLUDE_DATA_7=$EXCLUDE_DATA_7_RS
			EXCLUDE_DATA_8=$EXCLUDE_DATA_8_RS
			EXCLUDE_DATA_9=$EXCLUDE_DATA_9_RS
			EXCLUDE_DATA_10=$EXCLUDE_DATA_10_RS
			;;
		rdiff-backup)
			# First make sure no user error with the directory name occured with options
			if [ -z "$BACKUP_MOUNT_POINT" ];then
				error_handler 18 'BACKUP_MOUNT_POINT'
			fi
			BACKUP_LOCATION=$BACKUP_MOUNT_POINT$BACKUP_MOUNT_POINT_DIRECTORY
			;;
	esac
	if [ -z "$BACKUP_LOCATION" ];then
		error_handler 19
	fi
	check_backup_destination_directory "$BACKUP_MOUNT_POINT"
}

# these will be tested in the actual backup function for exist if local, or
# if have remote path syntax. rsync/rdiff will handle bad paths for remote
# destination directories.
# create backup directory then set backup directory names
set_backup_destination_data()
{
	local month=$( date +%m )

	# assemble the backup paths, if they are clones sub directory can be null
	HOME_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$HOME_DIR" )
	ROOT_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$ROOT_DIR" )
	DATA_1_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_1_DIR" )
	DATA_2_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_2_DIR" )
	DATA_3_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_3_DIR" )
	DATA_4_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_4_DIR" )
	DATA_5_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_5_DIR" )
	DATA_6_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_6_DIR" )
	DATA_7_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_7_DIR" )
	DATA_8_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_8_DIR" )
	DATA_9_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_9_DIR" )
	DATA_10_BACKUP=$( set_backup_destination_path "$BACKUP_LOCATION" "$DATA_10_DIR" )
}

# This makes sure that ending slashes do not occur in backup directory paths.
# args: $1 - $BACKUP_LOCATION; $2 - backup subdirectory. If null, use just use $1
set_backup_destination_path()
{
	local backupPath=$1

	if [ -n "$2" ];then
		backupPath="$backupPath/$2"
	fi
	echo $backupPath
}

set_backup_commands()
{
	local dryRun='' options=''

	case "$BACKUP_APP" in
		rsync)
			if [ "$B_CLEAN_OLDER" == 'true' ];then
				RSYNC_DELETE=' --delete --delete-excluded '
			fi
			if [ "$B_DRY_RUN" == 'true' ];then
				dryRun=' --dry-run '
			fi
			# set commands
			# note: extra options must END with ssh connection string
			# NOTE: -a = -rlptgoD
			# --acls only if needed
			options=" --hard-links --xattrs --sparse --numeric-ids --times -a $dryRun $RSYNC_DELETE $RSYNC_EXTRA_OPTIONS"

			HOME_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_HOME $options $HOME_PATH $HOME_BACKUP"
			ROOT_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_ROOT $options $ROOT_PATH $ROOT_BACKUP"
			DATA_1_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_1 $options $DATA_1_PATH $DATA_1_BACKUP"
			DATA_2_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_2 $options $DATA_2_PATH $DATA_2_BACKUP"
			DATA_3_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_3 $options $DATA_3_PATH $DATA_3_BACKUP"
			DATA_4_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_4 $options $DATA_4_PATH $DATA_4_BACKUP"
			DATA_5_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_5 $options $DATA_5_PATH $DATA_5_BACKUP"
			DATA_6_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_6 $options $DATA_6_PATH $DATA_6_BACKUP"
			DATA_7_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_7 $options $DATA_7_PATH $DATA_7_BACKUP"
			DATA_8_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_8 $options $DATA_8_PATH $DATA_8_BACKUP"
			DATA_9_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_9 $options $DATA_9_PATH $DATA_9_BACKUP"
			DATA_10_BU_COMMAND="$RSYNC_PATH --exclude-from=$SCRIPT_DATA_DIR$EXCLUDE_DATA_10 $options $DATA_10_PATH $DATA_10_BACKUP"

			# set text
			BACKUP_CLEAR='Backing up'
			# reset to false so main backup function can finish up
			B_CLEAN_OLDER='false'
			;;
		rdiff-backup)
			# set commands
			# http://www.mail-archive.com/rdiff-backup-users@nongnu.org/msg01212.html
			# --exclude-sockets to get rid of that dumb socket error
			if [ "$B_CLEAN_OLDER" != 'true' ];then
				# set commands
				options=" --exclude-sockets $RDIFF_EXTRA_OPTIONS "

				HOME_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_HOME $HOME_PATH $HOME_BACKUP"
				ROOT_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_ROOT $ROOT_PATH $ROOT_BACKUP"
				DATA_1_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_1 $DATA_1_PATH $DATA_1_BACKUP"
				DATA_2_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_2 $DATA_2_PATH $DATA_2_BACKUP"
				DATA_3_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_3 $DATA_3_PATH $DATA_3_BACKUP"
				DATA_4_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_4 $DATA_4_PATH $DATA_4_BACKUP"
				DATA_5_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_5 $DATA_5_PATH $DATA_5_BACKUP"
				DATA_6_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_6 $DATA_6_PATH $DATA_6_BACKUP"
				DATA_7_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_7 $DATA_7_PATH $DATA_7_BACKUP"
				DATA_8_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_8 $DATA_8_PATH $DATA_8_BACKUP"
				DATA_9_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_9 $DATA_9_PATH $DATA_9_BACKUP"
				DATA_10_BU_COMMAND="$RDIFF_PATH $options --exclude-globbing-filelist $SCRIPT_DATA_DIR$EXCLUDE_DATA_10 $DATA_10_PATH $DATA_10_BACKUP"

				# set text
				BACKUP_CLEAR='Backing up'
			else
				# set commands
				options=" --force --remove-older-than $RDIFF_REMOVE_TIME "

				HOME_BU_COMMAND="$RDIFF_PATH $options $HOME_BACKUP"
				ROOT_BU_COMMAND="$RDIFF_PATH $options $RDIFF_REMOVE_TIME $ROOT_BACKUP"
				DATA_1_BU_COMMAND="$RDIFF_PATH $options $DATA_1_BACKUP"
				DATA_2_BU_COMMAND="$RDIFF_PATH $options $DATA_2_BACKUP"
				DATA_3_BU_COMMAND="$RDIFF_PATH $options $DATA_3_BACKUP"
				DATA_4_BU_COMMAND="$RDIFF_PATH $options $DATA_4_BACKUP"
				DATA_5_BU_COMMAND="$RDIFF_PATH $options $DATA_5_BACKUP"
				DATA_6_BU_COMMAND="$RDIFF_PATH $options $DATA_6_BACKUP"
				DATA_7_BU_COMMAND="$RDIFF_PATH $options $DATA_7_BACKUP"
				DATA_8_BU_COMMAND="$RDIFF_PATH $options $DATA_8_BACKUP"
				DATA_9_BU_COMMAND="$RDIFF_PATH $options $DATA_9_BACKUP"
				DATA_10_BU_COMMAND="$RDIFF_PATH $options $DATA_10_BACKUP"

				# set text
				BACKUP_CLEAR="Removing all increments older than $RDIFF_REMOVE_TIME from"
			fi
			;;
	esac
}

# all error null directory handling is done in the final set_primary_backup_data function
# args: $1 - backup directory number
set_backup_mount_point()
{
	case $1 in
		1)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_1
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_1_RS
			;;
		2)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_2
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_2_RS
			;;
		3)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_3
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_3_RS
			;;
		4)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_4
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_4_RS
			;;
		5)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_5
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_5_RS
			;;
		6)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_6
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_6_RS
			;;
		7)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_7
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_7_RS
			;;
		8)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_8
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_8_RS
			;;
		9)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_9
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_9_RS
			;;
		10)
			BACKUP_MOUNT_POINT=$BACKUP_MOUNT_POINT_10
			BACKUP_MOUNT_POINT_RS=$BACKUP_MOUNT_POINT_10_RS
			;;
	esac
}

# args: $1 - backup directory number
set_backup_mount_point_directory()
{
	case $1 in
		1)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_1
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_1_RS
			;;
		2)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_2
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_2_RS
			;;
		3)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_3
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_3_RS
			;;
		4)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_4
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_4_RS
			;;
		5)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_5
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_5_RS
			;;
		6)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_6
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_6_RS
			;;
		7)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_7
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_7_RS
			;;
		8)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_8
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_8_RS
			;;
		9)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_9
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_9_RS
			;;
		10)
			BACKUP_MOUNT_POINT_DIRECTORY=$BACKUP_MOUNT_POINT_DIRECTORY_10
			BACKUP_MOUNT_POINT_DIRECTORY_RS=$BACKUP_MOUNT_POINT_DIRECTORY_10_RS
			;;
	esac
}

# args: $1 - data in format: x:y:z where x/y/z are null or 1-5
set_emailer_data(){
	local emailStart=$( cut -d ':' -f 1 <<< $1 )
	local emailFinish=$( cut -d ':' -f 2 <<< $1 )
	local emailError=$( cut -d ':' -f 3 <<< $1 )

	if [ -n "$emailStart" ];then
		case $emailStart in
			1)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_1"
				;;
			2)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_2"
				;;
			3)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_3"
				;;
			4)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_4"
				;;
			5)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_5"
				;;
			6)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_6"
				;;
			7)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_7"
				;;
			8)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_8"
				;;
			9)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_9"
				;;
			10)
				EMAIL_START_ACTION="$EMAIL_START_ACTION_10"
				;;
		esac
	fi
	if [ -n "$emailFinish" ];then
		case $emailFinish in
			1)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_1"
				;;
			2)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_2"
				;;
			3)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_3"
				;;
			4)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_4"
				;;
			5)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_5"
				;;
			6)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_6"
				;;
			7)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_7"
				;;
			8)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_8"
				;;
			9)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_9"
				;;
			10)
				EMAIL_FINISH_ACTION="$EMAIL_FINISH_ACTION_10"
				;;
		esac
	fi
	if [ -n "$emailError" ];then
		case $emailError in
			1)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_1"
				;;
			2)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_2"
				;;
			3)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_3"
				;;
			4)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_4"
				;;
			5)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_5"
				;;
			6)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_6"
				;;
			7)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_7"
				;;
			8)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_8"
				;;
			9)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_9"
				;;
			10)
				EMAIL_ERROR_ACTION="$EMAIL_ERROR_ACTION_10"
				;;
		esac
	fi
}

# args: $1 - mount number
set_mount_data()
{
	case $1 in
		1)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_1
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_1
			;;
		2)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_2
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_2
			;;
		3)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_3
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_3
			;;
		4)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_4
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_4
			;;
		5)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_5
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_5
			;;
		6)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_6
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_6
			;;
		7)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_7
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_7
			;;
		8)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_8
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_8
			;;
		9)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_9
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_9
			;;
		10)
			MOUNT_BU_DISK=$MOUNT_BU_DISK_10
			UNMOUNT_BU_DISK=$UNMOUNT_BU_DISK_10
			;;
	esac
}

# args: $1 - backup job number; $2 - set/print
set_or_print_backup_job()
{
	local backupJob='' backupJobData='' backupJobName=''

	case $1 in
		1)
			backupJob="$BACKUP_JOB_1"
			;;
		2)
			backupJob="$BACKUP_JOB_2"
			;;
		3)
			backupJob="$BACKUP_JOB_3"
			;;
		4)
			backupJob="$BACKUP_JOB_4"
			;;
		5)
			backupJob="$BACKUP_JOB_5"
			;;
		6)
			backupJob="$BACKUP_JOB_6"
			;;
		7)
			backupJob="$BACKUP_JOB_7"
			;;
		8)
			backupJob="$BACKUP_JOB_8"
			;;
		9)
			backupJob="$BACKUP_JOB_9"
			;;
		10)
			backupJob="$BACKUP_JOB_10"
			;;
	esac
	if [ -n "$( grep ':' <<< $backupJob )" ];then
		backupJobData=$( cut -d ':' -f 2-20 <<< $backupJob )
		BACKUP_JOB_NAME=$( cut -d ':' -f 1 <<< $backupJob )
	else
		backupJobData=$backupJob
	fi
	if [ -n "$BACKUP_JOB_NAME" ];then
		backupJobName=" ${C}$BACKUP_JOB_NAME${S}"
	fi
	# make sure the job has content
	if [ -n "$backupJob" -a "$backupJob" != ':' ];then
		if [ "$2" == 'set' ];then
			echo "${S}Your job presets are: ${C}$backupJobData"
			echo "${S}Restarting $SCRIPT_NAME to run backup job$backupJobName (Job No. ${C}$1${S}) now...${N}"
			echo $LINE
			sleep 1
			exec $SCRIPT_PATH/$SCRIPT_NAME -z $1 $backupJobData
			exit 0
		elif [ "$2" == 'print' ];then
			echo "${M}You are currently about to run backup job number: ${C}$BACKUP_JOB_NU"
			echo "${S}Your job$backupJobName (Job No. ${C}$1${S}) presets are: ${C}$backupJobData${N}"
		fi
	else
		error_handler 17 "$1"
	fi
}

# args: $1 - data in format: x:y:z where x/y/z are null or 1-5
set_pre_post_data(){
	local preMount=$( cut -d ':' -f 1 <<< $1 )
	local postMount=$( cut -d ':' -f 2 <<< $1 )
	local postUmount=$( cut -d ':' -f 3 <<< $1 )

	if [ -n "$preMount" ];then
		case $preMount in
			1)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_1"
				;;
			2)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_2"
				;;
			3)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_3"
				;;
			4)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_4"
				;;
			5)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_5"
				;;
			6)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_6"
				;;
			7)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_7"
				;;
			8)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_8"
				;;
			9)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_9"
				;;
			10)
				PRE_MOUNT_FUNCTION="$PRE_MOUNT_FUNCTION_10"
				;;
		esac
	fi
	if [ -n "$postMount" ];then
		case $postMount in
			1)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_1"
				;;
			2)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_2"
				;;
			3)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_3"
				;;
			4)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_4"
				;;
			5)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_5"
				;;
			6)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_6"
				;;
			7)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_7"
				;;
			8)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_8"
				;;
			9)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_9"
				;;
			10)
				POST_MOUNT_FUNCTION="$POST_MOUNT_FUNCTION_10"
				;;
		esac
	fi
	if [ -n "$postUmount" ];then
		case $postUmount in
			1)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_1"
				;;
			2)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_2"
				;;
			3)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_3"
				;;
			4)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_4"
				;;
			5)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_5"
				;;
			6)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_6"
				;;
			7)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_7"
				;;
			8)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_8"
				;;
			9)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_9"
				;;
			10)
				POST_UMOUNT_FUNCTION="$POST_UMOUNT_FUNCTION_10"
				;;
		esac
	fi
}

#### -------------------------------------------------------------------
#### set add, skip, clone data
#### -------------------------------------------------------------------

# remember, -A overrides -S if they are the same SKIP item.
# args: $1 - items to add, loops through all.
set_add_data()
{
	local addItem=''

	for addItem in $1
	do
		case $addItem in
			d)
				B_SKIP_DATA_FULL='false'
				B_SKIP_DATA_1='false'
				B_SKIP_DATA_2='false'
				B_SKIP_DATA_3='false'
				B_SKIP_DATA_4='false'
				B_SKIP_DATA_5='false'
				B_SKIP_DATA_6='false'
				B_SKIP_DATA_7='false'
				B_SKIP_DATA_8='false'
				B_SKIP_DATA_9='false'
				B_SKIP_DATA_10='false'
				;;
			h)
				B_SKIP_HOME='false'
				;;
			r)
				B_SKIP_ROOT='false'
				;;
			rh|hr)
				B_SKIP_HOME='false'
				B_SKIP_ROOT='false'
				;;
			# note that B_SKIP_DATA_FULL='false' is required
			# to override the block off switch for DATA
			1)
				B_SKIP_DATA_1='false'
				B_SKIP_DATA_FULL='false'
				;;
			2)
				B_SKIP_DATA_2='false'
				B_SKIP_DATA_FULL='false'
				;;
			3)
				B_SKIP_DATA_3='false'
				B_SKIP_DATA_FULL='false'
				;;
			4)
				B_SKIP_DATA_4='false'
				B_SKIP_DATA_FULL='false'
				;;
			5)
				B_SKIP_DATA_5='false'
				B_SKIP_DATA_FULL='false'
				;;
			6)
				B_SKIP_DATA_6='false'
				B_SKIP_DATA_FULL='false'
				;;
			7)
				B_SKIP_DATA_7='false'
				B_SKIP_DATA_FULL='false'
				;;
			8)
				B_SKIP_DATA_8='false'
				B_SKIP_DATA_FULL='false'
				;;
			9)
				B_SKIP_DATA_9='false'
				B_SKIP_DATA_FULL='false'
				;;
			10)
				B_SKIP_DATA_10='false'
				B_SKIP_DATA_FULL='false'
				;;
		esac
	done
}

# args: $1 - directory/ies to be cloned
set_clone_data()
{
	case $1 in
		h)
			B_CLONE_HOME='true'
			HOME_DIR='home'
			B_SKIP_DATA_FULL='true'
			B_SKIP_ROOT='true'
			CLONE_SOURCE_DIR=$HOME_PATH
			;;
		r)
			B_CLONE_ROOT='true'
			ROOT_DIR=''
			B_SKIP_DATA_FULL='true'
			B_SKIP_HOME='true'
			CLONE_SOURCE_DIR=$ROOT_PATH
			;;
		1)
			set_clone_skip_data
			B_CLONE_DATA_1='true'
			DATA_1_DIR=''
			CLONE_SOURCE_DIR=$DATA_1_PATH
			;;
		2)
			set_clone_skip_data
			B_CLONE_DATA_2='true'
			DATA_2_DIR=''
			CLONE_SOURCE_DIR=$DATA_2_PATH
			;;
		3)
			set_clone_skip_data
			B_CLONE_DATA_3='true'
			DATA_3_DIR=''
			CLONE_SOURCE_DIR=$DATA_3_PATH
			;;
		4)
			set_clone_skip_data
			B_CLONE_DATA_4='true'
			DATA_4_DIR=''
			CLONE_SOURCE_DIR=$DATA_4_PATH
			;;
		5)
			set_clone_skip_data
			B_CLONE_DATA_5='true'
			DATA_5_DIR=''
			CLONE_SOURCE_DIR=$DATA_5_PATH
			;;
		6)
			set_clone_skip_data
			B_CLONE_DATA_6='true'
			DATA_6_DIR=''
			CLONE_SOURCE_DIR=$DATA_6_PATH
			;;
		7)
			set_clone_skip_data
			B_CLONE_DATA_7='true'
			DATA_7_DIR=''
			CLONE_SOURCE_DIR=$DATA_7_PATH
			;;
		8)
			set_clone_skip_data
			B_CLONE_DATA_8='true'
			DATA_8_DIR=''
			CLONE_SOURCE_DIR=$DATA_8_PATH
			;;
		9)
			set_clone_skip_data
			B_CLONE_DATA_9='true'
			DATA_9_DIR=''
			CLONE_SOURCE_DIR=$DATA_9_PATH
			;;
		10)
			set_clone_skip_data
			B_CLONE_DATA_10='true'
			DATA_10_DIR=''
			CLONE_SOURCE_DIR=$DATA_10_PATH
			;;
	esac
	# make sure no user error occured
	check_backup_source_directory "$CLONE_SOURCE_DIR"
}

# set all data to false except for
# explicitly set clone item and FULL
set_clone_skip_data()
{
	B_SKIP_DATA_FULL='false'
	B_SKIP_DATA_1='true'
	B_SKIP_DATA_2='true'
	B_SKIP_DATA_3='true'
	B_SKIP_DATA_4='true'
	B_SKIP_DATA_5='true'
	B_SKIP_DATA_6='true'
	B_SKIP_DATA_7='true'
	B_SKIP_DATA_8='true'
	B_SKIP_DATA_9='true'
	B_SKIP_DATA_10='true'
	B_SKIP_HOME='true'
	B_SKIP_ROOT='true'
}

# remember, -A overrides -S if they are the same SKIP item.
# args: $1 - items to skip, loops through all.
set_skip_data()
{
	local skipItem=''

	for skipItem in $1
	do
		case $skipItem in
			d)
				B_SKIP_DATA_FULL='true'
				;;
			h)
				B_SKIP_HOME='true'
				;;
			r)
				B_SKIP_ROOT='true'
				;;
			rh|hr)
				B_SKIP_HOME='true'
				B_SKIP_ROOT='true'
				;;
			1)
				B_SKIP_DATA_1='true'
				;;
			2)
				B_SKIP_DATA_2='true'
				;;
			3)
				B_SKIP_DATA_3='true'
				;;
			4)
				B_SKIP_DATA_4='true'
				;;
			5)
				B_SKIP_DATA_5='true'
				;;
			6)
				B_SKIP_DATA_6='true'
				;;
			7)
				B_SKIP_DATA_7='true'
				;;
			8)
				B_SKIP_DATA_8='true'
				;;
			9)
				B_SKIP_DATA_9='true'
				;;
			10)
				B_SKIP_DATA_10='true'
				;;
		esac
	done
}

#### -------------------------------------------------------------------
#### primary backup tools
#### -------------------------------------------------------------------

run_backup_question()
{
	local opt='' options='' doTheBackup='' removeBackup='' repeat=''
	local removeDeleteOpt='' nullCloneSource='' cloneSource='' rsyncSim1=' backup' rsyncSim2=''

	# need to check destination data here, after mount, but not need to recheck if same as
	# initial
	if [ "$BACKUP_LOCATION" != "$BACKUP_MOUNT_POINT" ];then
		check_backup_destination_directory "$BACKUP_LOCATION"
	fi
	echo $MLINE
	print_version_info 'main'
	echo $MLINE
	echo "${M}Working backup location: ${C}$BACKUP_LOCATION${N}"
	echo $MLINE
	print_history_data 'main'
	echo $MLINE
	if [ "$BACKUP_JOB_NU" != 'none' ];then
		set_or_print_backup_job "$BACKUP_JOB_NU" 'print'
		echo $LINE
	fi
	if [ "$BACKUP_APP" == 'rsync' ] && [ "$B_DRY_RUN" == 'true' -o -n "$( grep 'dry-run' <<< $RSYNC_EXTRA_OPTIONS )" ];then
		echo "${M}You are using the ${C}rsync --dry-run${M} option, which simulates your backup."
		echo "${S}This option lets you see what would happen, before you really run the backup."
		echo $LINE
		rsyncSim1=" ${C}simulate${S} the backup of"
		rsyncSim2=" ${C}simulation${M} of a"
	fi
	if [ "$B_IS_CLONE" == 'true' ];then

		if [ -z "$CLONE_SOURCE_DIR" ];then
			nullCloneSource='echo -e "${M}Your Clone Source Directory is ${W}empty${M}.${S} Unless you are cloning ${C}root${S}, this is\nprobably a mistake. Make sure this is correct before you proceed please.\n"'
			cloneSource='empty'
		else
			cloneSource=$CLONE_SOURCE_DIR
		fi

		echo "${M}You are about to run a$rsyncSim2 direct ${C}Clone job${M} (${C}-C${M}) using these directories:${S}"
		echo "Source Directory: ${C}$cloneSource${S} :: Destination Directory: ${C}$BACKUP_MOUNT_POINT"
		echo
		eval "$nullCloneSource"
		echo "${S}Cloning will sync all destination files with your source directory files, and remove"
		echo "any obsolete files from the destination directory. ${W}BE CAREFUL WITH THIS!!!"
		echo $LINE

		echo "${C}1 - run-clone-job${S} - Clones the above Source Data to Destination directory."
		echo
		echo "${C}2 - quit${S} - Don't do the Clone after all, exit script."

		options="run-clone-job quit"
	else
		case "$BACKUP_APP" in
			rdiff-backup)
				echo "${S}Backups use standard ${C}$BACKUP_APP${S} settings, which lets you restore from any time"
				echo "period stored in the full backup. After first full backup, the next ones will be"
				echo "incremental backups, which run much faster since they only backup changed files."
				;;
			rsync)
				echo "${S}This will$rsyncSim1 your system to the backup directories you have already"
				echo "set up for your ${C}$BACKUP_APP${S} backup."
				;;
		esac
		echo $LINE
		echo "${S}Please select one of the following numbers to assign the correct backup option."
		echo "${C}1 - backup-normal${S} - Backs up as usual with $BACKUP_APP. Does not remove old backups."
		case "$BACKUP_APP" in
			rdiff-backup)
				echo "${C}2 - clean-older${S} - Removes all backup increments older than your time setting: $RDIFF_REMOVE_TIME"
				echo "    After the cleanup, runs a new standard backup."
				removeDeleteOpt='clean-older'
				;;
			rsync)
				echo "${C}2 - clean-obsolete${S} - Removes all backed up up files that have been deleted from"
				echo "    your current install."
				removeDeleteOpt='clean-obsolete'
				;;
		esac
		echo "${C}3 - backup-and-delete-old${S} - Backs up but first deletes old backups. This is final, "
		echo "    so once you agree to remove, no restore of older material will be possible. This will"
		echo "    delete the backup that corresponds to the currently active primary backup directory."
		echo
		echo "${C}4 - quit${S} - Don't do the backup after all, exit script."

		options="backup-normal $removeDeleteOpt backup-and-delete-old quit"
	fi
	echo $LINE
	select opt in $options
	do
		log_function_data 'data' "User Option Selection: $opt"
		case $opt in
			backup-normal)
				doTheBackup='true'
				;;
			backup-and-delete-old)
				removeBackup='true'
				doTheBackup='true'
				;;
			# rdiff-backup only
			clean-older)
				# first get rid of all older files and increments
				B_CLEAN_OLDER='true'
				run_backup_components
				B_CLEAN_OLDER='false'
				doTheBackup='true'
				;;
			# rsync only
			clean-obsolete)
				B_CLEAN_OLDER='true'
				doTheBackup='true'
				;;
			run-clone-job)
				B_CLEAN_OLDER='true'
				doTheBackup='true'
				;;
			quit)
				echo "${S}Ok, no backup today, exiting the script...${N}"
				exit 0
				;;
			*)
				echo $ELINE
				echo "${E}You need to type in one of above the numbers!!${N}"
				repeat='true'
				;;
		esac
		break
	done

	if [ "$repeat" == 'true' ];then
		run_backup_question
	fi
	if [ "$removeBackup" == 'true' ];then
		remove_backups
	fi
	if [ "$doTheBackup" == 'true' ];then
		run_backup_components
	fi
}

remove_backups()
{
	local options='' opt='' repeat='' deleteBackup='' directory='' directories=''
	local backupDirectories=$( ls $BACKUP_LOCATION )

	# dump line breaks
	for directory in $backupDirectories
	do
		directories="$directories$directory "
	done
	if [ -z "$backupDirectories" ];then
		directories='No Directories to Delete '
	fi

	echo $LINE
	echo "${Q}Are you sure you want to delete the contents of your backup directories?${N}"
	echo
	echo "${S}These directories will be removed: ${C}$directories${S}in ${C}$BACKUP_LOCATION"
	echo
	echo "${C}1 - yes-delete${S} - Deletes ALL directories in ${C}$BACKUP_LOCATION"
	echo "${C}2 - no-keep${S} - Keeps current data in ${C}$BACKUP_LOCATION${S} and backs up as normal."
	echo "${C}3 - quit${S} - Quit, think about it later."
	echo $LINE
	options='yes-delete no-keep quit'
	select opt in $options
	do
		log_function_data 'data' "User Option Selection: $opt"
		case $opt in
			yes-delete)
				deleteBackup='true'
				;;
			no-keep)
				echo $LINE
				echo "${S}Ok, no deleting of them today."
				echo
				echo "Continuing with backup now...${N}"
				;;
			quit)
				echo "${S}Ok, no backup today, exiting the script...${N}"
				exit 0
				;;
			*)
				echo $ELINE
				echo "${E}You need to type in one of above the numbers!!${N}"
				repeat='true'
				;;
		esac
		break
	done

	if [ "$repeat" == 'true' ];then
		remove_backups
	fi
	if [ "$deleteBackup" == 'true' ];then
		delete_old_backup
	fi
}

delete_old_backup()
{
	local removedDirectories=$( ls $BACKUP_LOCATION )  directory=''

	echo $LINE
	if [ -n "$removedDirectories" ];then
		log_function_data 'data' "delete_old_backup - Directories to be deleted:\n$removedDirectories"
		GET_PID=''
		echo -n "${S}Starting deletion of "
		for directory in $removedDirectories
		do
			echo -n "${C}$directory${S} "
		done
		echo -n "in ${C}$BACKUP_LOCATION${N}"
		echo
		echo -n "${S}This could take a while, be patient$ENDING_2${N}"
		if [ "$B_SPINNING_WHEEL" != 'true' ];then
			echo
			echo # clear that -n
		fi
		for directory in $removedDirectories
		do
			# as ghstryder pointed out, this should also be dry run supporting so people don't
			# get unexpected result of deleting their actual backup with -r (--dry-run) option
			if [ "$B_DRY_RUN" != 'true' ];then
				if [ "$B_SPINNING_WHEEL" == 'true' ];then
					rm -fr $BACKUP_LOCATION/$directory &
					GET_PID="$!"
					spinning_wheel_activity_indicator delete
					wait
				else
					echo -n "${S}Deleting ${C}$BACKUP_LOCATION/$directory${S} now.....${N}"
					rm -fr $BACKUP_LOCATION/$directory
					echo "${S}... ${M}directory deleted${N}"
				fi
			else
				echo -n "${S}Dry run (${C}-r${S}) emulation mode: Deleting ${C}$BACKUP_LOCATION/$directory${S} now.....${N}"
			fi
		done
	else
		echo -n "${M}There is nothing to delete, continuing with backup...${N}"
		log_function_data 'data' "delete_old_backup - No Directories to be deleted"
	fi

	DELETION_TEXT=' deletion and'
	echo
	echo "${S}Starting backup now...${N}"
	sleep $SLEEP_TIME_BACKUP
	B_DELETE_STATUS='true'
}

run_backup_components()
{
	# set rdiff-backup/rsync commands. Must be here because delete data might be
	# set for rsync
	set_backup_commands

	# If you don't need excludes in /home, then just delete the exclude stuff, --exclude...
	echo $LINE
	log_function_data 'data' "run_backup_components: begin\n\n"
	#backup home directory
	if [ "$B_CLONE_HOME" == 'true' ] || [ "$HOME_DIR" != '' -a "$B_SKIP_HOME" != 'true' ];then
		check_backup_source_directory "$HOME_PATH"
		log_function_data 'data' "Starting Home Backup Command:\n$HOME_BU_COMMAND"
		echo -n "${S}$BACKUP_CLEAR ${C}home${S} directory$ENDING_1${N}"
		if [ "$B_SPINNING_WHEEL" == 'true' ];then
			GET_PID=''
			eval $HOME_BU_COMMAND &
			GET_PID="$!"
			spinning_wheel_activity_indicator backup home
		else
			eval $HOME_BU_COMMAND || error_handler 25 "$?"
			echo
		fi
		log_function_data 'data' "Finished Home\n\n"
		sleep $SLEEP_TIME_BACKUP
	fi

	# backup system root directory
	if [ "$B_CLONE_ROOT" == 'true' ] || [ "$ROOT_DIR" != '' -a "$B_SKIP_ROOT" != 'true'  ];then
		check_backup_source_directory "$ROOT_PATH"
		log_function_data 'data' "Starting Root Backup Command:\n$ROOT_BU_COMMAND"
		echo -n "${S}$BACKUP_CLEAR ${C}root${S} directory ${C}$ROOT_DESC${S}$ENDING_1${N}"
		if [ "$B_SPINNING_WHEEL" == 'true' ];then
			GET_PID=''
			eval $ROOT_BU_COMMAND &
			GET_PID="$!"
			spinning_wheel_activity_indicator backup $ROOT_DESC
		else
			eval $ROOT_BU_COMMAND || error_handler 25 "$?"
			echo
		fi
		log_function_data 'data' "Finished Root\n\n"
	fi

	if [ "$B_SKIP_DATA_FULL" != 'true' ];then
		# backup optional user data 1
		if [ "$B_CLONE_DATA_1" == 'true' ] || [ "$DATA_1_DIR" != '' -a "$B_SKIP_DATA_1" != 'true' ];then
			check_backup_source_directory "$DATA_1_PATH"
			log_function_data 'data' "Starting Data 1 Backup Command:\n$DATA_1_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_1_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_1_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_1_DESC
			else
				eval $DATA_1_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 1\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi

		# backup optional user data 2
		if [ "$B_CLONE_DATA_2" == 'true' ] || [ "$DATA_2_DIR" != '' -a "$B_SKIP_DATA_2" != 'true' ];then
			check_backup_source_directory "$DATA_2_PATH"
			log_function_data 'data' "Starting Data 2 Backup Command:\n$DATA_2_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_2_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_2_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_2_DESC
			else
				eval $DATA_2_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 2\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi

		# backup optional user data 3
		if [ "$B_CLONE_DATA_3" == 'true' ] || [ "$DATA_3_DIR" != '' -a "$B_SKIP_DATA_3" != 'true' ];then
			check_backup_source_directory "$DATA_3_PATH"
			log_function_data 'data' "Starting Data 3 Backup Command:\n$DATA_3_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_3_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_3_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_3_DESC
			else
				eval $DATA_3_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 3\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi

		# backup optional user data 4
		if [ "$B_CLONE_DATA_4" == 'true' ] || [ "$DATA_4_DIR" != '' -a "$B_SKIP_DATA_4" != 'true' ];then
			check_backup_source_directory "$DATA_4_PATH"
			log_function_data 'data' "Starting Data 4 Backup Command:\n$DATA_4_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_4_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_4_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_4_DESC
			else
				eval $DATA_4_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 4\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi

		# backup optional user data 5
		if [ "$B_CLONE_DATA_5" == 'true' ] || [ "$DATA_5_DIR" != '' -a "$B_SKIP_DATA_5" != 'true' ];then
			check_backup_source_directory "$DATA_5_PATH"
			log_function_data 'data' "Starting Data 5 Backup Command:\n$DATA_5_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_5_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_5_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_5_DESC
			else
				eval $DATA_5_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 5\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi

		# backup optional user data 2
		if [ "$B_CLONE_DATA_6" == 'true' ] || [ "$DATA_6_DIR" != '' -a "$B_SKIP_DATA_6" != 'true' ];then
			check_backup_source_directory "$DATA_6_PATH"
			log_function_data 'data' "Starting Data 6 Backup Command:\n$DATA_6_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_6_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_6_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_6_DESC
			else
				eval $DATA_6_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 6\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi

		# backup optional user data 7
		if [ "$B_CLONE_DATA_7" == 'true' ] || [ "$DATA_7_DIR" != '' -a "$B_SKIP_DATA_7" != 'true' ];then
			check_backup_source_directory "$DATA_7_PATH"
			log_function_data 'data' "Starting Data 7 Backup Command:\n$DATA_7_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_7_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_7_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_7_DESC
			else
				eval $DATA_7_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 7\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi

		# backup optional user data 8
		if [ "$B_CLONE_DATA_8" == 'true' ] || [ "$DATA_8_DIR" != '' -a "$B_SKIP_DATA_8" != 'true' ];then
			check_backup_source_directory "$DATA_8_PATH"
			log_function_data 'data' "Starting Data 8 Backup Command:\n$DATA_8_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_8_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_8_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_8_DESC
			else
				eval $DATA_8_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 8\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi

		# backup optional user data 9
		if [ "$B_CLONE_DATA_9" == 'true' ] || [ "$DATA_9_DIR" != '' -a "$B_SKIP_DATA_9" != 'true' ];then
			check_backup_source_directory "$DATA_9_PATH"
			log_function_data 'data' "Starting Data 9 Backup Command:\n$DATA_9_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_9_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_9_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_9_DESC
			else
				eval $DATA_9_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 9\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi

		# backup optional user data 10
		if [ "$B_CLONE_DATA_10" == 'true' ] || [ "$DATA_10_DIR" != '' -a "$B_SKIP_DATA_10" != 'true' ];then
			check_backup_source_directory "$DATA_10_PATH"
			log_function_data 'data' "Starting Data 10 Backup Command:\n$DATA_10_BU_COMMAND"
			echo -n "${S}$BACKUP_CLEAR ${C}$DATA_10_DESC${S} directory$ENDING_1${N}"
			if [ "$B_SPINNING_WHEEL" == 'true' ];then
				GET_PID=''
				eval $DATA_10_BU_COMMAND &
				GET_PID="$!"
				spinning_wheel_activity_indicator backup $DATA_10_DESC
			else
				eval $DATA_10_BU_COMMAND || error_handler 25 "$?"
				echo
			fi
			log_function_data 'data' "Finished Data 10\n\n"
			sleep $SLEEP_TIME_BACKUP
		fi
	fi
	log_function_data 'data' "run_backup_components: end\n$LI\n"
	# this is set to false either in the main rsync assigner or by rdiff feature
	if [ "$B_CLEAN_OLDER" != 'true' ];then
		finish_backup
	else
		echo $LINE
		echo "${S}Ok, finished cleaning up older backup increments, running main backup now...${N}"
		sleep $SLEEP_TIME_BACKUP
	fi
}

#### -------------------------------------------------------------------
#### Backup start/pre/post/finish functions
#### -------------------------------------------------------------------

mount_backup_disk()
{
	local retNu=0

	if [ "$MOUNT_BU_DISK" != '' -a "$B_SKIP_MOUNT" != 'true'  ];then
		# found a possible error case here with null backup directory:
		log_function_data 'data' "BACKUP_MOUNT_POINT: $BACKUP_MOUNT_POINT\nMount Data: $MOUNT_BU_DISK"
		if [ -z "$BACKUP_MOUNT_POINT" ];then
			error_handler 26
		fi
		echo -n "${S}Mounting backup drive/partition to ${C}$BACKUP_MOUNT_POINT${S}....${N}"
		eval $MOUNT_BU_DISK || retNu=$?
		if [ "$retNu" -eq 0 ];then
			echo "${S}....${M}mounted${N}"
			log_function_data 'data' "Mounted"
		else
			echo "${S}....${W}MOUNT FAILED!${N}"
			error_handler 2 "$retNu"
		fi
		# set the trap here
		trap 'trap_handler umount' INT TERM EXIT
	fi
}

# args: $1 - start/finish/error; $2 - data to be processed, error message, script start options
run_emailer_tasks()
{
	# strip out colors if present
	
	local data=$( echo -e "$2" | sed 's/\x1b\[[0-9]\{1,2\}\(;[0-9]\{1,2\}\)\{0,2\}m//g' )
	local actionTime=$( date +"%Y %B %e - %R:%S" )
	# then construct the string
	data="Rbxi $1: $actionTime\n$data"
	
	# note that the action must be in quotes when you execute it with eval
	case $1 in
		start)
			if [ -n "$EMAIL_START_ACTION" ];then
				log_function_data 'data' "Begin emailer task: start action"
				echo $LINE
				echo "${S}Running user action: ${C}start${N}"
				eval "$EMAIL_START_ACTION"
			fi
			;;
		finish)
			if [ -n "$EMAIL_FINISH_ACTION" ];then
				log_function_data 'data' "Begin emailer task: finish action"
				echo $LINE
				echo "${S}Running user action: ${C}finish${N}"
				eval "$EMAIL_FINISH_ACTION"
			fi
			;;
		error)
			if [ -n "$EMAIL_ERROR_ACTION" ];then
				log_function_data 'data' "Begin emailer task: error action"
				echo $LINE
				echo "${S}Running user action: ${C}error${N}"
				eval "$EMAIL_ERROR_ACTION"
			fi
			;;
	esac
}

# args: $1 - pre-mount/post-mount/post-umount
run_pre_post_tasks()
{
	# note that the function must be in quotes when you declare it with eval
	case $1 in
		pre-mount)
			if [ -n "$PRE_MOUNT_FUNCTION" ];then
				log_function_data 'data' "Begin pre post tasks: pre mount function"
				echo $LINE
				echo "${S}Running user defined function: ${C}pre_mount_tasks()${N}"
				eval "$PRE_MOUNT_FUNCTION"
				pre_mount_tasks || error_handler 27 "$?"
			fi
			;;
		post-mount)
			if [ -n "$POST_MOUNT_FUNCTION" ];then
				log_function_data 'data' "Begin pre post tasks: post mount function"
				echo $LINE
				echo "${S}Running user defined function: ${C}post_mount_tasks()${N}"
				eval "$POST_MOUNT_FUNCTION"
				post_mount_tasks || error_handler 28 "$?"
			fi
			;;
		post-umount)
			if [ -n "$POST_UMOUNT_FUNCTION" ];then
				log_function_data 'data' "Begin pre post tasks: error function"
				echo $LINE
				echo "${S}Running user defined function: ${C}post_umount_tasks()${N}"
				eval "$POST_UMOUNT_FUNCTION"
				post_umount_tasks || error_handler 29 "$?"
			fi
			;;
	esac
}

#### -------------------------------------------------------------------
#### Backup completion functions
#### -------------------------------------------------------------------

finish_backup()
{
	# set the DURATION global here as well prior to updating configs
	print_the_end_time
	update_configs
	umount_backup_disk
	run_pre_post_tasks 'post-umount'
	print_complete_message
	log_function_data 'data' "Backup Job Completed.\n\n"
	run_emailer_tasks 'finish' "Completed. Start Options: $SCRIPT_OPTIONS"
}

update_configs()
{
	local backupDate=$( date +"%Y-%m-%d - %R" )
	local cloneJob='' backupJobName=''
	if [ "$B_IS_CLONE" == 'true' -a -n "$CLONE_SOURCE_DIR" ];then
		cloneJob=" :: Cloned: $CLONE_SOURCE_DIR"
	fi
	if [ -n "$BACKUP_JOB_NAME" ];then
		backupJobName=" ($BACKUP_JOB_NAME)"
	fi
	local backupString="Location: $BACKUP_LOCATION :: Date: $backupDate~Run Time: $BACKUP_DURATION :: Deletion: $B_DELETE_STATUS :: Job No: $BACKUP_JOB_NU$backupJobName$cloneJob"

	echo $LINE
	echo "${S}Updating backup records now...${N}"
	sed -i "s%last-backup-directory=.*%last-backup-directory=$BACKUP_LOCATION%" $SCRIPT_CONFIGS
	sed -i "s/last-backup-date=.*/last-backup-date=$backupDate/" $SCRIPT_CONFIGS
	sed -i "s/last-backup-duration=.*/last-backup-duration=$BACKUP_DURATION/" $SCRIPT_CONFIGS
	sed -i "s/last-backup-app=.*/last-backup-app=$BACKUP_APP/" $SCRIPT_CONFIGS
	sed -i "s/last-backup-job=.*/last-backup-job=$BACKUP_JOB_NU/" $SCRIPT_CONFIGS

	case "$BACKUP_APP" in
		rdiff-backup)
			sed -i "s%rdbu-backup-history=.*%rdbu-backup-history=$backupString%" $SCRIPT_CONFIGS
			;;
		rsync)
			sed -i "s%rsync-backup-history=.*%rsync-backup-history=$backupString%" $SCRIPT_CONFIGS
			;;
	esac
	log_function_data 'data' "Completed Backup Config Data:\n$( cat $SCRIPT_CONFIGS )\n$LI\n"
}

# do some arithmetic on time
print_the_end_time()
{
	local endTime=$( date +%s )
	local completedTime=$(( $endTime - $START_TIME ))
	local hours=$(( $completedTime / 3600 ))
	local remainingMinutes=$(( $completedTime % 3600 ))
	local minutes=$(( $remainingMinutes / 60 ))
	local seconds=$(( $remainingMinutes % 60 ))
	local hourText='' minuteText='' secondText='' plural=''

	# set hours, if needed
	if [ "$hours" -ne 0 ];then
		if [ "$hours" -gt 1 ];then
			plural='s'
		else
			plural=''
		fi
		hourText=" ${C}$hours${S} hour$plural,"
	fi

	# set minutes
	if [ "$minutes" -gt 1 -o "$minutes" -eq 0 ];then
		plural='s'
	else
		plural=''
	fi
	minuteText=" ${C}$minutes${S} minute$plural,"

	# set seconds
	if [ "$seconds" -gt 1 -o "$seconds" -eq 0 ];then
		plural='s'
	else
		plural=''
	fi
	secondText=" ${C}$seconds${S} second$plural"

	echo "${S}The$DELETION_TEXT backup took$hourText$minuteText$secondText to complete.${N}"
	# zero pad the data
	minutes=$( printf %02d $minutes )
	seconds=$( printf %02d $seconds )
	BACKUP_DURATION=$hours:$minutes:$seconds
}

umount_backup_disk()
{
	local retNu=0

	if [ "$MOUNT_BU_DISK" != '' -a "$B_SKIP_MOUNT" != 'true' ];then
		log_function_data 'data' "BACKUP_MOUNT_POINT: $BACKUP_MOUNT_POINT\nUmount Data: $UNMOUNT_BU_DISK"
		echo
		echo -n "${S}Unmounting your backup partition $BACKUP_MOUNT_POINT now...${N}"
		eval $UNMOUNT_BU_DISK || retNu=$?
		if [ "$retNu" -eq 0 ];then
			echo "${S}.....${M}successfully unmounted.${N}"
			log_function_data 'data' "Umount successful."
		else
			echo "${S}.....${W}UMOUNT FAILED!${N}"
			error_handler 3 "$retNu"
		fi
		trap - INT TERM EXIT
	fi
}

print_complete_message()
{
	echo $MLINE
	echo "${M}Ok, all done backing up for today!"
	echo $MLINE
}

###################################################################
#####   EXECUTE SCRIPT COMPONENTS
###################################################################
set_script_colors
check_script_requires
get_options "$@"
run_emailer_tasks 'start' "Start Options: $SCRIPT_OPTIONS"

# Make sure user is logged in as root first and that backup location is present
check_startup_stuff
log_function_data 'start' "$SCRIPT_OPTIONS"
# this sets the correct startup path so that exclude lists load correctly
check_script_path
# any updates that need to be run will be run here, should only be required
# at rare intervals.
check_script_changes

# set rsync/rdiff-backup variables
set_primary_backup_data

# initialize the backup directory values
set_backup_destination_data

run_pre_post_tasks 'pre-mount'
# then, if you use this, mount your backup drive
mount_backup_disk
run_pre_post_tasks 'post-mount'
# note that this block only runs if the -a,-c, or -d flags are used, or if these
# are set in a job or preset file.
# for option deletion-run/run/clean-run. You can only run one of these, not more.
if [ "$B_DELETE_BACKUP" == 'true' ];then
	delete_old_backup
# this is for rdiff only, we need to run first the cleanup job, then
# next send it to the main backup.
elif [ "$B_CLEAN_OLDER" == 'true' -a "$BACKUP_TYPE" == 'rdiff-backup' ];then
	run_backup_components
	# must reset so we don't run the rdiff-cleanup stuff again
	B_CLEAN_OLDER='false'
fi
# skip the intro question and do it automatically
if [ "$B_DO_BACKUP" == 'true' ];then
	run_backup_components
# otherwise ask what options to use
else
	run_backup_question
fi

## extra information:

#SpecialFileError var/run/acpid.socket Socket error: AF_UNIX path too long
#SpecialFileError var/run/dbus/system_bus_socket Socket error: AF_UNIX path too long
#SpecialFileError var/run/dirmngr/socket Socket error: AF_UNIX path too long
#SpecialFileError var/run/mysqld/mysqld.sock Socket error: AF_UNIX path too long
#SpecialFileError var/run/pcscd.comm Socket error: AF_UNIX path too long
#SpecialFileError var/run/xdmctl/dmctl/socket Socket error: AF_UNIX path too long
#SpecialFileError var/run/xdmctl/dmctl-:0/socket Socket error: AF_UNIX path too long

exit 0

###**EOF**###